package study.repository.user;

import java.util.List;

import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import study.domain.user.User;
import study.domain.user.UserSearch;
import study.domain.user.User_;

import com.barney.support.jpa.CustomRepositorySupport;
import com.google.common.collect.Lists;

public class UserRepositoryImpl extends CustomRepositorySupport implements UserRepositoryCustom {

	@Override
	public long getCount(UserSearch search) {
		CriteriaBuilder builder = getEntityManager().getCriteriaBuilder();
		CriteriaQuery<Long> c = builder.createQuery(Long.class);
		Root<User> root = c.from(User.class);
		c.select(builder.count(root));
		c.where(toPredicate(restrictions(search, builder, root)));
		return getEntityManager().createQuery(c).getSingleResult();
	}

	@Override
	public List<User> getList(UserSearch search) {
		CriteriaBuilder builder = getEntityManager().getCriteriaBuilder();
		CriteriaQuery<User> c = builder.createQuery(User.class);
		Root<User> root = c.from(User.class);
		c.select(root);
		c.where(toPredicate(restrictions(search, builder, root)));
		TypedQuery<User> query = getEntityManager().createQuery(c);
		query.setFirstResult(search.getOffset());
		query.setMaxResults(search.getPageSize());
		return query.getResultList();
	}

	private Predicate[] toPredicate(List<Predicate> predicate) {
		return predicate.toArray(new Predicate[0]);
	}

	private <T extends User> List<Predicate> restrictions(
			final UserSearch search, CriteriaBuilder builder, Root<T> root) {
		List<Predicate> specs = Lists.newArrayList();
		if (greateThanMinLength(search.getName())) {
			specs.add(builder.like(root.get(User_.name), likeExpression(search.getName())));
		}
		if (greateThanMinLength(search.getUsername())) {
			specs.add(builder.like(root.get(User_.username), likeExpression(search.getUsername())));
		}
		if (search.getEnabled() != null) {
			specs.add(builder.equal(root.get(User_.enabled), search.getEnabled()));
		}
		return specs;
	}

}
